package no.nordicsemi.android.uart.view

import android.util.Log
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import no.nordicsemi.android.common.theme.view.RadioButtonGroup
import no.nordicsemi.android.common.theme.view.RadioButtonItem
import no.nordicsemi.android.common.theme.view.RadioGroupViewEntity
import no.nordicsemi.android.uart.R
import no.nordicsemi.android.uart.UartServer
import no.nordicsemi.android.uart.data.MacroEol
import no.nordicsemi.android.uart.data.UARTRecord
import no.nordicsemi.android.uart.data.UARTRecordType
import no.nordicsemi.android.ui.view.ScreenSection
import no.nordicsemi.android.ui.view.SectionTitle
import no.nordicsemi.android.utils.EMPTY
import java.text.SimpleDateFormat
import java.util.LinkedList
import java.util.Locale
import java.util.Queue
class ne101 {
    companion object{
        init {
            System.loadLibrary("profile_uart")
        }
        external fun stringFromJNI(): String
        external fun fft(data_in :FloatArray): FloatArray
    }
}
data class NumeratorDenominator(
    val b: DoubleArray,
    val a: DoubleArray
) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as NumeratorDenominator

        if (!b.contentEquals(other.b)) return false
        if (!a.contentEquals(other.a)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = b.contentHashCode()
        result = 31 * result + a.contentHashCode()
        return result
    }
}
interface ButterworthCoefficients {
    val numeratorDenominator: NumeratorDenominator
    val nOrder: Int
}

fun DoubleArray.filterIIR(
    butterworthCoefficients: ButterworthCoefficients
): DoubleArray {
    val nOrder = butterworthCoefficients.nOrder
    val bufferSize = nOrder * 2 + 1
    val buffer = DoubleArray(bufferSize)
    val out = DoubleArray(size)

    for (n in indices) {
        for (i in 0 until bufferSize - 1) {
            buffer[i] = buffer[i + 1]
        }

        buffer[bufferSize - 1] = 0.0
        for (i in 0 until bufferSize) {
            buffer[i] += this[n] * butterworthCoefficients.numeratorDenominator.b[i]
        }

        for (i in 0 until bufferSize - 1) {
            buffer[i + 1] += -buffer[0] * butterworthCoefficients.numeratorDenominator.a[i + 1]
        }
        out[n] = buffer[0]
    }

    return out
}

val points_in: Queue<Float> = LinkedList()
val points_raw: Queue<Float> = LinkedList()
val points_fft: Queue<Float> = LinkedList()
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun CurveSection(records: List<UARTRecord>, onEvent: (UARTViewEvent) -> Unit) {
    var count = 0
    var SAMPLESIZE = 256
    var DISPLAYSIZE =32
    if(records.isEmpty())
    {}
    else
    {
        records.forEach {
            var substring = it.toString().split(':')
            //println(substring)
            var string_idx = 0
            var idx = 0

            if (substring[0].contains("CH0")) {
                for (idx in 1 until 13) {
                    if (points_raw.size >= SAMPLESIZE)
                        points_raw.poll()
                    if (points_in.size >= DISPLAYSIZE)
                        points_in.poll()
                    points_raw.offer(-substring[idx].toFloat())
                    points_in.offer((-substring[idx].toFloat()))
                    count = count + 1
                }
            }
            Column(
                modifier = Modifier.fillMaxWidth(),
                horizontalAlignment = Alignment.Start
            ) {
                if (count >= SAMPLESIZE) {
                    count = count - SAMPLESIZE
                    var data = points_raw.toFloatArray()
                    for(inx in 0  until data.size)
                        data[inx]=-data[inx]
                    var fft_result = ne101.fft(data)
                    fft_result[0]=0F;
                    var maxf=(fft_result.max()*0.025).toFloat()
                    points_fft.clear()
                    //for(idx in SAMPLESIZE/2-1-10 until SAMPLESIZE/2-1)
                    //    points_fft.offer(fft_result[SAMPLESIZE/2-idx-1]/maxf)
                    for(idx in 1 until 10)//SAMPLESIZE/2)
                        points_fft.offer(fft_result[idx]/maxf)
                }
                if(count>= DISPLAYSIZE){
                    AxisView()
                    Spacer(modifier = Modifier.height(16.dp))
                    AxisView2()
                    Spacer(modifier = Modifier.height(16.dp))
                    AxisView3()

                }
            }
        }
    }
    /*Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxSize()
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically
        ) {
            SectionTitle(
                resId = R.drawable.ic_output,
                title = stringResource(R.string.uart_output),
                modifier = Modifier,
                menu = { Menu(onEvent) }
            )
        }

        Spacer(modifier = Modifier.size(16.dp))

        /*val scrollState = rememberLazyListState()

        LazyColumn(
            modifier = Modifier.fillMaxWidth(),
            state = scrollState
        ) {
            if (records.isEmpty()) {
                item { Text(text = stringResource(id = R.string.uart_output_placeholder)) }
            } else {
                records.forEach {
                    item {
                        when (it.type) {
                            UARTRecordType.INPUT -> MessageItemInput(record = it)
                            UARTRecordType.OUTPUT -> MessageItemOutput(record = it)
                        }

                        Spacer(modifier = Modifier.height(16.dp))
                    }
                }
            }
        }

        LaunchedEffect(records) {
            if (scrollState.isScrolledToTheEnd() || records.isEmpty()) {
                return@LaunchedEffect
            }
            launch {
                scrollState.scrollToItem(records.lastIndex)
            }
        }*/
    }*/
}



private val datFormatter = SimpleDateFormat("dd MMMM yyyy, HH:mm:ss", Locale.ENGLISH)

private fun UARTRecord.timeToString(): String {
    return datFormatter.format(timestamp)
}

@Composable
private fun AxisView(){
    /*var points = listOf(20F, 80F, 30F, 70F, 20F, 90F, 10F, 60F, 20F, 133F, 240F, 73F,
        20F, 80F, 30F, 70F, 20F, 90F, 10F, 60F, 20F, 133F, 240F, 73F,
        20F, 80F, 30F, 70F, 20F, 90F, 10F, 60F, 20F, 133F, 240F, 73F,
        20F, 80F, 30F, 70F, 20F, 90F, 10F, 60F, 20F, 133F, 240F, 73F,
        20F, 80F, 30F, 70F, 20F, 90F, 10F, 60F, 20F, 133F, 240F, 73F,
        20F, 80F, 30F, 70F, 20F, 90F, 10F, 60F, 20F, 133F, 240F, 73F)
    points_test.clear()
    for(idx in 0 until points.size)
        points_test.offer(points[idx])*/
    BezierCurve(
        modifier = Modifier
            .fillMaxWidth()
            .padding(start = 10.dp, top = 10.dp, end = 10.dp)
            .height(80.dp),
        points = points_in ,
        minPoint = 0F,
        maxPoint = 50F,
        style = BezierCurveStyle.Fill(
            brush = Brush.verticalGradient(listOf(Color(0x3300FF00), Color(0xFF00FF00))),
        ),
    )
}
@Composable
private fun AxisView2(){
    BezierCurve(
        modifier = Modifier
            .fillMaxWidth()
            .padding(start = 10.dp, top = 10.dp, end = 10.dp)
            .height(80.dp),
        points = points_raw ,
        minPoint = 0F,
        maxPoint = 50F,
        style = BezierCurveStyle.Fill(
            brush = Brush.verticalGradient(listOf(Color(0x3300FF00), Color(0xFF00FF00))),
        ),
    )
}
@Composable
private fun AxisView3(){
    BezierCurve(
        modifier = Modifier
            .fillMaxWidth()
            .padding(start = 10.dp, top = 10.dp, end = 10.dp)
            .height(80.dp),
        points = points_fft ,
        minPoint = 0F,
        maxPoint = 50F,
        style = BezierCurveStyle.Fill(
            brush = Brush.verticalGradient(listOf(Color(0x3300FF00), Color(0xFF00FF00))),
        ),
    )
}